home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / editors / emacs / xemacs / xemacs-1.004 / xemacs-1 / xemacs-19.13 / dynodump / dynodump.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-08  |  15.1 KB  |  499 lines

  1. /*
  2.  *    Copyright (c) 1995 by Sun Microsystems, Inc.
  3.  *    All rights reserved.
  4.  *
  5.  * This source code is a product of Sun Microsystems, Inc. and is provided
  6.  * for unrestricted use provided that this legend is included on all tape
  7.  * media and as a part of the software program in whole or part.  Users
  8.  * may copy or modify this source code without charge, but are not authorized
  9.  * to license or distribute it to anyone else except as part of a product or
  10.  * program developed by the user.
  11.  *
  12.  * THIS PROGRAM CONTAINS SOURCE CODE COPYRIGHTED BY SUN MICROSYSTEMS, INC.
  13.  * SUN MICROSYSTEMS, INC., MAKES NO REPRESENTATIONS ABOUT THE SUITABLITY
  14.  * OF SUCH SOURCE CODE FOR ANY PURPOSE.  IT IS PROVIDED "AS IS" WITHOUT
  15.  * EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  SUN MICROSYSTEMS, INC. DISCLAIMS
  16.  * ALL WARRANTIES WITH REGARD TO SUCH SOURCE CODE, INCLUDING ALL IMPLIED
  17.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  IN
  18.  * NO EVENT SHALL SUN MICROSYSTEMS, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT,
  19.  * INCIDENTAL, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
  20.  * FROM USE OF SUCH SOURCE CODE, REGARDLESS OF THE THEORY OF LIABILITY.
  21.  * 
  22.  * This source code is provided with no support and without any obligation on
  23.  * the part of Sun Microsystems, Inc. to assist in its use, correction, 
  24.  * modification or enhancement.
  25.  *
  26.  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
  27.  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS
  28.  * SOURCE CODE OR ANY PART THEREOF.
  29.  *
  30.  * Sun Microsystems, Inc.
  31.  * 2550 Garcia Avenue
  32.  * Mountain View, California 94043
  33.  */
  34.  
  35. /*
  36.  * dynodump(3x) dumps a running executable into a specified ELF file.  The new
  37.  * file consists of the memory contents of the original file together with any
  38.  * heap.  This heap is assigned to a new `.heap' section within the new file.
  39.  *
  40.  * The new file may be re-executed, and will contain any data modifications
  41.  * made to the original image up until the time dynodump(3x) was called.
  42.  *
  43.  * The original image may have undergone relocations (performed by ld.so.1)
  44.  * prior to control being transferred to the image.  These relocations will
  45.  * reside as the data copied from the image.  To prevent subsequent executions
  46.  * of the new image from undergoing the same relocations, any relocation entries
  47.  * (besides copy or jump slot relocations) are nulled out.  Note that copy
  48.  * relocations such as required for __iob must be reinitialized each time the
  49.  * process starts, so it is not sufficient to simply null out the .dynamic
  50.  * sections relocation information.  The effect of this is that if the new
  51.  * image was bound to definitions in any shared object dependencies, then these
  52.  * dependencies *must* reside in the same location as when dynodump(3x) was
  53.  * called.  Any changes to the shared object dependencies of the new image, or
  54.  * uses of such things as LD_PRELOAD, may result in the bindings encoded in the
  55.  * image becoming invalid.
  56.  *
  57.  * The following flags modify the data of the image created:
  58.  *
  59.  *  RTLD_SAVREL    save the original relocation data.  Under this option any
  60.  *        relocation offset is reset to contain the same data as was
  61.  *        found in the images original file.
  62.  *
  63.  *        This option allows relocation information to be retained in the
  64.  *        new image so that it may be re-executed when the new image is
  65.  *        run.  This allows far greater flexibility as the new image can
  66.  *        now take advantage of new shared objects.
  67.  *
  68.  *        Note. under this mechanism, any data item that undergoes
  69.  *        relocation and is then further modified during the execution of
  70.  *        the image before dynodump(3x) is called will lose the
  71.  *        modification that occured during the applications execution.
  72.  *
  73.  * N.B. The above commentary is not quite correct in the flags have been hardwired
  74.  *      to RTLD_SAVREL.
  75.  */
  76. #pragma ident    "@(#) $Id: dynodump.c,v 1.5 1995/06/26 20:11:08 georgn Exp $ - SMI"
  77.  
  78. #include    <sys/param.h>
  79. #include    <sys/procfs.h>
  80. #include    <fcntl.h>
  81. #include    <stdio.h>
  82. #include    <libelf.h>
  83. #include    <link.h>
  84. #include    <stdlib.h>
  85. #include    <string.h>
  86. #include    <unistd.h>
  87. #include    <errno.h>
  88. #include    <malloc.h>
  89. #include    "machdep.h"
  90. #include    "_dynodump.h"
  91.  
  92. /*
  93.  * Generic elf error message generator
  94.  */
  95. static int
  96. elferr(const char * str)
  97. {
  98.     fprintf(stderr, "%s: %s\n", str, elf_errmsg(elf_errno()));
  99.     return (1);
  100. }
  101.  
  102. int dynodump (const char *file);
  103. int
  104. dynodump (const char *file)
  105. {
  106.     Elf        *ielf, *oelf;
  107.     Ehdr    *iehdr, *oehdr;
  108.     Phdr    *iphdr, *ophdr, *data_phdr = 0;
  109.     Cache    *icache, *ocache, *_icache, *_ocache;
  110.     Cache    *data_cache = 0, *shstr_cache = 0;
  111.     Elf_Scn    *scn;
  112.     Shdr    *shdr;
  113.     Elf_Data    *data, rundata;
  114.     Half    ndx, _ndx;
  115.     int        fd, _fd;
  116.     Addr    edata, _addr;
  117.     char    *istrs, *ostrs, *_ostrs, proc[16];
  118.     const char     heap[] = ".heap";
  119.     prstatus_t    pstat;
  120.  
  121.     /*
  122.      * Obtain a file descriptor for this process,
  123.      * for the executable and get a prstatus_t
  124.      * structure.
  125.      */
  126.     sprintf(proc, "/proc/%ld", getpid());
  127.     if (((_fd = open(proc, O_RDONLY, 0)) == -1) ||
  128.     ((fd = ioctl(_fd, PIOCOPENM, (void *)0)) == -1) ||
  129.     (ioctl(_fd, PIOCSTATUS, &pstat) == -1)) {
  130.     fprintf(stderr, "/proc: initialization error: %s\n",
  131.         strerror(errno));
  132.     close(_fd);
  133.     return (1);
  134.     }
  135.     close(_fd);
  136.  
  137.     /*
  138.      * Initialize with the ELF library and make sure this is an executable
  139.      * ELF file we're dealing with.
  140.      */
  141.     elf_version(EV_CURRENT);
  142.     if ((ielf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
  143.     close(fd);
  144.     return (elferr("elf_begin"));
  145.     }
  146.     close(fd);
  147.  
  148.     if ((elf_kind(ielf) != ELF_K_ELF) ||
  149.     ((iehdr = elf_getehdr(ielf)) == NULL) ||
  150.     (iehdr->e_type != ET_EXEC)) {
  151.     fprintf(stderr, "image is not an ELF executable\n");
  152.     elf_end(ielf);
  153.     return (1);
  154.     }
  155.     /*
  156.      * Elf_elf_header(iehdr);
  157.      */
  158.  
  159.     /*
  160.      * Create the new output file.
  161.      */
  162.     if ((fd = open(file, O_RDWR | O_CREAT | O_TRUNC, 0777)) == -1) {
  163.     fprintf(stderr, "%s: open failed: %s\n", file,
  164.                strerror(errno));
  165.     elf_end(ielf);
  166.     return (1);
  167.     }
  168.     if ((oelf = elf_begin(fd, ELF_C_WRITE, NULL)) == NULL) {
  169.     elf_end(ielf);
  170.     close(fd);
  171.     return (elferr("elf_begin"));
  172.     }
  173.  
  174.     /*
  175.      * Obtain the input program headers.  Remember the data segments
  176.      * program header entry as this will be updated later to reflect the
  177.      * new .heap sections size.
  178.      */
  179.     if ((iphdr = elf_getphdr(ielf)) == NULL)
  180.     return (elferr("elf_getphdr"));
  181.  
  182.     for (ndx = 0, ophdr = iphdr; ndx != iehdr->e_phnum; ndx++, ophdr++) {
  183.     /*
  184.      * Save the program header that contains the NOBITS section, or
  185.      * the last loadable program header if no NOBITS exists.
  186.      * A NOBITS section translates to a memory size requirement that
  187.      * is greater than the file data it is mapped from.
  188.      */
  189.     if (ophdr->p_type == PT_LOAD) {
  190.         if (ophdr->p_filesz != ophdr->p_memsz)
  191.         data_phdr = ophdr;
  192.         else if (data_phdr) {
  193.         if (data_phdr->p_vaddr < ophdr->p_vaddr)
  194.             data_phdr = ophdr;
  195.         } else
  196.         data_phdr = ophdr;
  197.     }
  198.     }
  199.     if (data_phdr == 0) {
  200.     fprintf(stderr, "no data segment found!\n");
  201.     return (0);
  202.     }
  203.  
  204.     /*
  205.      * Obtain the input files section header string table.
  206.      */
  207.     if ((scn = elf_getscn(ielf, iehdr->e_shstrndx)) == NULL)
  208.     return (elferr("elf_getscn"));
  209.     if ((data = elf_getdata(scn, NULL)) == NULL)
  210.     return (elferr("elf_getdata"));
  211.     istrs = data->d_buf;
  212.  
  213.     /*
  214.      * Construct a cache to maintain the input files section information.
  215.      */
  216.     if ((icache = (Cache *) malloc(iehdr->e_shnum * sizeof (Cache))) == 0) {
  217.     fprintf(stderr, "malloc failed: %s\n", strerror(errno));
  218.     return (1);
  219.     }
  220.     _icache = icache;
  221.     _icache++;
  222.  
  223.     /*
  224.      * Traverse each section from the input file.
  225.      */
  226.     for (ndx = 1, scn = 0;
  227.      (_icache->c_scn = elf_nextscn(ielf, scn));
  228.      ndx++, scn = _icache->c_scn, _icache++) {
  229.  
  230.     if ((_icache->c_shdr = shdr = elf_getshdr(_icache->c_scn)) == NULL)
  231.         return (elferr("elf_getshdr"));
  232.  
  233.     if ((_icache->c_data = elf_getdata(_icache->c_scn, NULL)) == NULL)
  234.         return (elferr("elf_getdata"));
  235.  
  236.     _icache->c_name = istrs + (size_t)(shdr->sh_name);
  237.  
  238.     /*
  239.      * For each section that has a virtual address reestablish the
  240.      * data buffer to point to the memory image.
  241.      *
  242.      * if (shdr->sh_addr)
  243.      *     _icache->c_data->d_buf = (void *)shdr->sh_addr;
  244.      */
  245.  
  246.     /*
  247.      * Remember the last section of the data segment, the new .heap
  248.      * section will be added after this section.
  249.      */
  250.     if ((shdr->sh_addr + shdr->sh_size)
  251.         == (data_phdr->p_vaddr + data_phdr->p_memsz))
  252.         data_cache = _icache;
  253.  
  254.     /*
  255.      * Remember the section header string table as this will be
  256.      * rewritten with the new .heap name.
  257.      */
  258.     if ((shdr->sh_type == SHT_STRTAB) &&
  259.         ((strcmp(_icache->c_name, ".shstrtab")) == 0))
  260.         shstr_cache = _icache;
  261.     }
  262.     if (data_cache == 0) {
  263.     fprintf(stderr, "final data section not found!\n");
  264.     return (0);
  265.     }
  266.  
  267.     /*
  268.      * Determine the new .heap section to create.
  269.      */
  270. #ifdef notdef
  271.     rundata.d_buf = (void *)(data_cache->c_shdr->sh_addr +
  272.                  data_cache->c_shdr->sh_size);
  273.     rundata.d_size = (int)sbrk(0) - (int)rundata.d_buf;
  274. #else
  275.     rundata.d_buf = pstat.pr_brkbase;
  276.     rundata.d_size = pstat.pr_brksize;
  277. #endif
  278.     rundata.d_type = ELF_T_BYTE;
  279.     rundata.d_off = 0;
  280.     rundata.d_align = 1;
  281.     rundata.d_version = EV_CURRENT;
  282.  
  283.     /*
  284.      * From the new data buffer determine the new value for _end and _edata.
  285.      * This will also be used to update the data segment program header.
  286.      */
  287.     edata = S_ROUND((data_phdr->p_vaddr + data_phdr->p_memsz),
  288.             rundata.d_align) + rundata.d_size;
  289.  
  290.     /*
  291.      * We're now ready to construct the new elf image.
  292.      *
  293.      * Obtain a new elf header and initialize it with any basic information
  294.      * that isn't calculated as part of elf_update().  Bump the section
  295.      * header string table index to account for the .heap section we'll be
  296.      * adding.
  297.      */
  298.     if ((oehdr = elf_newehdr(oelf)) == NULL)
  299.     return (elferr("elf_newehdr"));
  300.  
  301.     oehdr->e_entry = iehdr->e_entry;
  302.     oehdr->e_machine = iehdr->e_machine;
  303.     oehdr->e_type = iehdr->e_type;
  304.     oehdr->e_shstrndx = iehdr->e_shstrndx + 1;
  305.  
  306.     /*
  307.      * Obtain a new set of program headers.  Initialize these with the same
  308.      * information as the input program headers and update the data segment
  309.      * to reflect the new .heap section.
  310.      */
  311.     if ((ophdr = elf_newphdr(oelf, iehdr->e_phnum)) == NULL)
  312.     return (elferr("elf_newphdr"));
  313.  
  314.     for (ndx = 0; ndx != iehdr->e_phnum; ndx++, iphdr++, ophdr++) {
  315.     *ophdr = *iphdr;
  316.     if (data_phdr == iphdr)
  317.         ophdr->p_filesz = ophdr->p_memsz = edata - ophdr->p_vaddr;
  318.     }
  319.  
  320.     /*
  321.      * Obtain a new set of sections.
  322.      */
  323.     _icache = icache;
  324.     _icache++;
  325.     for (ndx = 1; ndx != iehdr->e_shnum; ndx++, _icache++) {
  326.     /*
  327.      * Create a matching section header in the output file.
  328.      */
  329.     if ((scn = elf_newscn(oelf)) == NULL)
  330.         return (elferr("elf_newscn"));
  331.     if ((shdr = elf_getshdr(scn)) == NULL)
  332.         return (elferr("elf_getshdr"));
  333.     *shdr = *_icache->c_shdr;
  334.  
  335.     /*
  336.      * Create a matching data buffer for this section.
  337.      */
  338.     if ((data = elf_newdata(scn)) == NULL)
  339.         return (elferr("elf_newdata"));
  340.     *data = *_icache->c_data;
  341.  
  342.     /*
  343.      * For each section that has a virtual address reestablish the
  344.      * data buffer to point to the memory image.  Note, we skip
  345.      * the plt section.
  346.      */
  347.     if ((shdr->sh_addr) && (!((shdr->sh_type == SHT_PROGBITS)
  348.                   && (strcmp(_icache->c_name, ".plt") == 0))))
  349.         data->d_buf = (void *)shdr->sh_addr;
  350.  
  351.     /*
  352.      * Update any NOBITS section to indicate that it now contains
  353.      * data.
  354.      */
  355.     if (shdr->sh_type == SHT_NOBITS)
  356.         shdr->sh_type = SHT_PROGBITS;
  357.  
  358.     /*
  359.      * Add the new .heap section after the last section of the
  360.      * present data segment.
  361.      */
  362.     if (data_cache == _icache) {
  363.         if ((scn = elf_newscn(oelf)) == NULL)
  364.         return (elferr("elf_newscn"));
  365.         if ((shdr = elf_getshdr(scn)) == NULL)
  366.         return (elferr("elf_getshdr"));
  367.         shdr->sh_type = SHT_PROGBITS;
  368.         shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
  369.  
  370.         if ((data = elf_newdata(scn)) == NULL)
  371.         return (elferr("elf_newdata"));
  372.         *data = rundata;
  373.     }
  374.  
  375.     /*
  376.      * Update the section header string table size to reflect the
  377.      * new section name.
  378.      */
  379.     if (shstr_cache && (shstr_cache == _icache))
  380.         data->d_size += sizeof (heap);
  381.     }
  382.  
  383.     /*
  384.      * Write out the new image, and obtain a new elf descriptor that will
  385.      * allow us to write to the new image.
  386.      */
  387.     if (elf_update(oelf, ELF_C_WRITE) == -1)
  388.     return (elferr("elf_update"));
  389.     elf_end(oelf);
  390.     if ((oelf = elf_begin(fd, ELF_C_RDWR, NULL)) == NULL)
  391.     return (elferr("elf_begin"));
  392.     if ((oehdr = elf_getehdr(oelf)) == NULL)
  393.     return (elferr("elf_getehdr"));
  394.  
  395.     /*
  396.      * Obtain the output files section header string table.
  397.      */
  398.     if ((scn = elf_getscn(oelf, oehdr->e_shstrndx)) == NULL)
  399.     return (elferr("elf_getscn"));
  400.     if ((data = elf_getdata(scn, NULL)) == NULL)
  401.     return (elferr("elf_getdata"));
  402.     ostrs = _ostrs = data->d_buf;
  403.     *_ostrs++ = '\0';
  404.  
  405.     /*
  406.      * Construct a cache to maintain the output files section information.
  407.      */
  408.     if ((ocache = (Cache *)malloc(oehdr->e_shnum * sizeof (Cache))) == 0) {
  409.     fprintf(stderr, "malloc failed: %s\n", strerror(errno));
  410.     return (1);
  411.     }
  412.     _ocache = ocache;
  413.     _ocache++;
  414.     _icache = icache;
  415.     _icache++;
  416.  
  417.     /*
  418.      * Traverse each section from the input file rebuilding the section
  419.      * header string table as we go.
  420.      */
  421.     _ndx = _addr = 0;
  422.     for (ndx = 1, scn = 0;
  423.      (_ocache->c_scn = elf_nextscn(oelf, scn));
  424.      ndx++, scn = _ocache->c_scn, _ocache++, _icache++) {
  425.  
  426.     const char *strs;
  427.  
  428.     if ((_ocache->c_shdr = shdr =
  429.          elf_getshdr(_ocache->c_scn)) == NULL)
  430.         return (elferr("elf_getshdr"));
  431.     if ((_ocache->c_data =
  432.          elf_getdata(_ocache->c_scn, NULL)) == NULL)
  433.         return (elferr("elf_getdata"));
  434.  
  435.     /*
  436.      * If were inserting the new .heap section, insert the new
  437.      * section name and initialize it's virtual address.
  438.      */
  439.     if (_addr) {
  440.         strs = heap;
  441.         shdr->sh_addr = S_ROUND(_addr, shdr->sh_addralign);
  442.         _addr = 0;
  443.     } else
  444.         strs = istrs + (size_t)(_icache->c_shdr->sh_name);
  445.  
  446.     strcpy(_ostrs, strs);
  447.     shdr->sh_name = _ostrs - ostrs;
  448.     _ocache->c_name = _ostrs;
  449.     _ostrs += strlen(strs) + 1;
  450.  
  451.     /*
  452.      * If we've inserted a new section any later section may need
  453.      * their sh_link fields updated.
  454.      */
  455.     if (_ndx) {
  456.         if (_ocache->c_shdr->sh_link >= _ndx)
  457.         _ocache->c_shdr->sh_link++;
  458.     }
  459.  
  460.     /*
  461.      * If this is the last section of the original data segment
  462.      * determine sufficient information to initialize the new .heap
  463.      * section which will be obtained next.
  464.      */
  465.     if (data_cache == _icache) {
  466.         _ndx = ndx + 1;
  467.         _addr = shdr->sh_addr + shdr->sh_size;
  468.         _icache--;
  469.         data_cache = 0;
  470.     }
  471.     }
  472.  
  473.     /*
  474.      * Now that we have a complete description of the new image update any
  475.      * sections that are required.
  476.      *
  477.      *  o    update the value of _edata and _end.
  478.      *
  479.      *  o    reset any relocation entries if necessary.
  480.      */
  481.     _ocache = &ocache[1];
  482.     _icache = &icache[1];
  483.     for (ndx = 1; ndx < oehdr->e_shnum; ndx++, _ocache++, _icache++) {
  484.     if ((_ocache->c_shdr->sh_type == SHT_SYMTAB) ||
  485.         (_ocache->c_shdr->sh_type == SHT_DYNSYM))
  486.         update_sym(ocache, _ocache, edata);
  487.  
  488.     if (_ocache->c_shdr->sh_type == M_REL_SHT_TYPE)
  489.         update_reloc(ocache, _ocache, icache, _icache, oehdr->e_shnum);
  490.     }
  491.  
  492.     if (elf_update(oelf, ELF_C_WRITE) == -1)
  493.     return (elferr("elf_update"));
  494.  
  495.     elf_end(oelf);
  496.     elf_end(ielf);
  497.     return (0);
  498. }
  499.